/// Support for doing something awesome.
///
/// More dartdocs go here.
library;

export 'src/object_base.dart';

// TODO: Export any libraries intended for clients of this package.
import 'dart:math';

// 点类及相关操作
class Point {
  double? x;
  double? y;
  double z = 0;

  Point(this.x, this.y);

  Point.origin() : x = 0, y = 0;

  Point.alongXAxis(double x) : this(x, 0);

  double distanceTo(Point other) {
    var dx = (x ?? 0) - (other.x ?? 0);
    var dy = (y ?? 0) - (other.y ?? 0);
    return sqrt(dx * dx + dy * dy);
  }

  double get right => (x ?? 0) + z;
  set right(double value) => x = value - z;
  double get bottom => (y ?? 0) + z;
  set bottom(double value) => y = value - z;

  static double distanceBetween(Point a, Point b) {
    var dx = (a.x ?? 0) - (b.x ?? 0);
    var dy = (a.y ?? 0) - (b.y ?? 0);
    return sqrt(dx * dx + dy * dy);
  }
}

class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0);
  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

// 人物类及接口实现
class Person {
  final String _name;
  Person(this._name);
  String greet(String who) => 'Hello, $who. I am $_name.';
}

class Impostor implements Person {
  String get _name => '';
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

// 向量类继承
class Vector2d {
  final double x;
  final double y;

  Vector2d(this.x, this.y);
  Vector2d.named({required this.x, required this.y});
}

class Vector3d extends Vector2d {
  final double z;
  Vector3d(super.x, super.y, this.z);
  Vector3d.yzPlane({required super.y, required this.z}) : super.named(x: 0);
}

// 矩形类及属性操作
class Rectangle {
  double left, top, width, height;
  Rectangle(this.left, this.top, this.width, this.height);
  double get right => left + width;
  set right(double value) => left = value - width;
  double get bottom => top + height;
  set bottom(double value) => top = value - height;
}

// 抽象类与继承
abstract class Doer {
  void doSomething();
}

class EffectiveDoer extends Doer {
  void doSomething() {
    print('Doing something...');
  }
}

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }

  void _illuminateDisplay() {
    print('Illuminating display...');
  }

  void _activateIrSensor() {
    print('Activating IR sensor...');
  }
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }

  void _bootNetworkInterface() {
    print('Booting network interface...');
  }

  void _initializeMemory() {
    print('Initializing memory...');
  }

  void _upgradeApps() {
    print('Upgrading apps...');
  }
}

// 混入类
mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

mixin Musician {
  void playInstrument(String instrumentName);
  void playPiano() {
    playInstrument('Piano');
  }
  void playFlute() {
    playInstrument('Flute');
  }
}

mixin NameIdentity {
  String get name;
  @override
  int get hashCode => name.hashCode;
  @override
  bool operator ==(other) => other is NameIdentity && name == other.name;
}

abstract interface class Tuner {
  void tuneInstrument();
}

mixin Guitarist implements Tuner {
  void playSong() {
    tuneInstrument();
    print('Strums guitar majestically.');
  }
}

class MusicianBase {
  void musicianMethod() {
    print('Playing music!');
  }
}

mixin MusicalPerformer on MusicianBase {
  void performerMethod() {
    print('Performing music!');
    super.musicianMethod();
  }
}

class SingerDancer extends MusicianBase with MusicalPerformer {
}

class Virtuoso with Musician {
  @override
  void playInstrument(String instrumentName) {
    print('Plays the $instrumentName beautifully');
  }
}

class PersonWithIdentity with NameIdentity {
  final String name;
  PersonWithIdentity(this.name);
}

class PunkRocker with Guitarist {
  @override
  void tuneInstrument() {
    print("Don't bother, being out of tune is punk rock.");
  }
}

// 枚举类
enum Color { red, green, blue }

enum Vehicle implements Comparable<Vehicle> {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires;
  final int passengers;
  final int carbonPerKilometer;

  int get carbonFootprint => (carbonPerKilometer / passengers).round();
  bool get isTwoWheeled => this == Vehicle.bicycle;
  @override
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}

// 扩展方法
extension type E1(int i) {
  E1.n(this.i);
  E1.m(int j, String foo) : i = j + foo.length;
}

extension type const E2._(int it) {
  E2(): this._(42);
  E2.otherName(this.it);
}

extension type E3._(int i) {
  E3.fromString(String foo) : i = int.parse(foo);
}

extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }

  double parseDouble() {
    return double.parse(this);
  }
}

extension MyFancyList<T> on List<T> {
  int get doubleLength => length * 2;
  List<T> operator -() => reversed.toList();
  List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}

extension type IdNumber(int id) {
  operator <(IdNumber other) => id < other.id;
}

extension type NumberE(int value) {
  NumberE operator +(NumberE other) => NumberE(value + other.value);
  NumberE get next => NumberE(value + 1);
  bool isValid() => !value.isNegative;
}

extension type NumberT(int value) implements int {
  NumberT get i => this;
}

void main() {
  // 点类及相关操作测试
  var p = Point(2, 2);
  assert(p.y == 2);
  double distance = p.distanceTo(Point(4, 4));
  print('Distance: $distance');
  var a = p?.y;
  print('a: $a');
  var p1 = Point(2, 2);
  var p2 = Point(1, 2);
  var pImmutable = const ImmutablePoint(2, 2);
  var aImmutable = const ImmutablePoint(1, 1);
  var bImmutable = const ImmutablePoint(1, 1);
  assert(identical(aImmutable, bImmutable));
  print('a and b are the same instance: ${identical(aImmutable, bImmutable)}');
  const pointAndLine = {
    'point': [const ImmutablePoint(0, 0)],
    'line': [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
  };
  var aNew = const ImmutablePoint(1, 1);
  var bNew = ImmutablePoint(1, 1);
  assert(!identical(aNew, bNew));
  print('a and b are not the same instance: ${!identical(aNew, bNew)}');
  print('The type of a is ${aNew.runtimeType}');
  var point = Point.origin();
  point.x = 4;
  assert(point.x == 4);
  assert(point.y == 0);
  print('Point x: ${point.x}, y: ${point.y}');
  var pointA = Point(2, 2);
  var pointB = Point(4, 4);
  var distanceBetween = Point.distanceBetween(pointA, pointB);
  assert(2.8 < distanceBetween && distanceBetween < 2.9);
  print('Distance between a and b: $distanceBetween');
  var rect = Point(3, 4);
  rect.right = 12;
  assert(rect.x == -8);
  print('Rect x: ${rect.x}, y: ${rect.y}');

  // 人物类及接口实现测试
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));

  // 向量类继承测试
  var vector2d = Vector2d(1, 2);
  var vector3d = Vector3d(1, 2, 3);
  var vector3dYZ = Vector3d.yzPlane(y: 2, z: 3);

  // 矩形类及属性操作测试
  var rectangle = Rectangle(3, 4, 20, 15);
  assert(rectangle.left == 3);
  rectangle.right = 12;
  assert(rectangle.left == -8);
  print('Rect left: ${rectangle.left}, right: ${rectangle.right}');

  // 抽象类与继承测试
  var doer = EffectiveDoer();
  doer.doSomething();
  var tv = SmartTelevision();
  tv.turnOn();

  // 混入类测试
  var singerDancer = SingerDancer();
  singerDancer.performerMethod();
  var virtuoso = Virtuoso();
  virtuoso.playPiano();
  var personIdentity1 = PersonWithIdentity('John');
  var personIdentity2 = PersonWithIdentity('John');
  print('Person1 and Person2 are equal: ${personIdentity1 == personIdentity2}');
  var punkRocker = PunkRocker();
  punkRocker.playSong();

  // 枚举类测试
  final favoriteColor = Color.blue;
  if (favoriteColor == Color.blue) {
    print('Your favorite color is blue!');
  }
  assert(Color.red.index == 0);
  assert(Color.green.index == 1);
  assert(Color.blue.index == 2);
  List<Color> colors = Color.values;
  assert(colors[2] == Color.blue);
  var aColor = Color.blue;
  switch (aColor) {
    case Color.red:
      print('Red as roses!');
      break;
    case Color.green:
      print('Green as grass!');
      break;
    default:
      print(aColor);
  }
  print(Color.blue.name);
  print(Vehicle.car.carbonFootprint);

  // 扩展方法测试
  print('42'.parseInt());
  print('42.5'.parseDouble());
  var list = [1, 2, 3];
  print(list.doubleLength);
  print(-list);
  print(list.split(2));
  var safeId = IdNumber(42424242);
  print(safeId < IdNumber(42424241));
  E1(4);
  E1.n(3);
  E1.m(5, "Hello!");
  E2();
  const E2._(2);
  E2.otherName(3);
  E3.fromString('5');
  var num = NumberE(1);
  print(num + num);
  print(num.next);
  print(num.isValid());
  var v1 = NumberT(1);
  int v2 = NumberT(2);
  var v3 = v1.i - v1;
  var v4 = v2 + v1;
  var v5 = 2 + v1;
  print(v3);
  print(v4);
  print(v5);
}
    